package com.zhengbing.tj.aspect;

import com.zhengbing.tj.entity.AuditLog;
import com.zhengbing.tj.service.AsyncAuditLogService;
import com.zhengbing.tj.common.AuditLogUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import java.lang.reflect.Method;
import java.io.Serializable;

/**
 * 审计日志切面类
 * 使用AOP拦截需要审计的方法，实现业务代码和审计日志代码的解耦
 *
 * @author zhengbing
 * @date 2024-08-22
 */
@Aspect
@Component
public class AuditLogAspect {
    
    @Autowired
    private AsyncAuditLogService asyncAuditLogService;
    
    /**
     * 定义用户服务的切点
     */
    @Pointcut("execution(* com.zhengbing.tj.service.impl.UserServiceImpl.save(..))")
    public void userSavePointcut() {}
    
    @Pointcut("execution(* com.zhengbing.tj.service.impl.UserServiceImpl.updateById(..))")
    public void userUpdatePointcut() {}
    
    @Pointcut("execution(* com.zhengbing.tj.service.impl.UserServiceImpl.removeById(..))")
    public void userDeletePointcut() {}
    
    /**
     * 用户保存操作的环绕通知
     * @param joinPoint 连接点
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Around("userSavePointcut()")
    public Object aroundUserSave(ProceedingJoinPoint joinPoint) throws Throwable {
        // 执行原方法
        Object result = joinPoint.proceed();
        
        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0 && args[0] instanceof Object && result instanceof Boolean && (Boolean) result) {
            Object entity = args[0];
            
            try {
                // 获取实体ID
                Method getIdMethod = entity.getClass().getMethod("getId");
                Long id = (Long) getIdMethod.invoke(entity);
                
                // 创建并异步记录审计日志
                AuditLog log = AuditLogUtil.createAuditLog("user", id,
                        AuditLogUtil.OPERATION_TYPE_INSERT, null, entity);
                asyncAuditLogService.recordAuditLogAsync(log);
            } catch (Exception e) {
                // 记录异常但不影响主业务流程
                e.printStackTrace();
            }
        }
        
        return result;
    }
    
    /**
     * 用户更新操作的环绕通知
     * @param joinPoint 连接点
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Around("userUpdatePointcut()")
    public Object aroundUserUpdate(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        Object entity = null;
        Object beforeEntity = null;
        
        if (args != null && args.length > 0 && args[0] instanceof Object) {
            entity = args[0];
            
            try {
                // 获取实体ID和更新前的数据
                Method getIdMethod = entity.getClass().getMethod("getId");
                Long id = (Long) getIdMethod.invoke(entity);
                
                // 获取UserServiceImpl实例
                Object target = joinPoint.getTarget();
                Method getByIdMethod = target.getClass().getMethod("getById", Serializable.class);
                beforeEntity = getByIdMethod.invoke(target, id);
            } catch (Exception e) {
                // 记录异常但不影响主业务流程
                e.printStackTrace();
            }
        }
        
        // 执行原方法
        Object result = joinPoint.proceed();
        
        // 如果更新成功，记录审计日志
        if (result instanceof Boolean && (Boolean) result && entity != null && beforeEntity != null) {
            try {
                // 获取实体ID
                Method getIdMethod = entity.getClass().getMethod("getId");
                Long id = (Long) getIdMethod.invoke(entity);
                
                // 创建并异步记录审计日志
                AuditLog log = AuditLogUtil.createAuditLog("user", id,
                        AuditLogUtil.OPERATION_TYPE_UPDATE, beforeEntity, entity);
                asyncAuditLogService.recordAuditLogAsync(log);
            } catch (Exception e) {
                // 记录异常但不影响主业务流程
                e.printStackTrace();
            }
        }
        
        return result;
    }
    
    /**
     * 用户删除操作的环绕通知
     * @param joinPoint 连接点
     * @return 方法执行结果
     * @throws Throwable 异常
     */
    @Around("userDeletePointcut()")
    public Object aroundUserDelete(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        Serializable id = null;
        Object beforeEntity = null;
        
        if (args != null && args.length > 0 && args[0] instanceof Serializable) {
            id = (Serializable) args[0];
            
            try {
                // 获取删除前的数据
                Object target = joinPoint.getTarget();
                Method getByIdMethod = target.getClass().getMethod("getById", Serializable.class);
                beforeEntity = getByIdMethod.invoke(target, id);
            } catch (Exception e) {
                // 记录异常但不影响主业务流程
                e.printStackTrace();
            }
        }
        
        // 执行原方法
        Object result = joinPoint.proceed();
        
        // 如果删除成功，记录审计日志
        if (result instanceof Boolean && (Boolean) result && id != null && beforeEntity != null) {
            try {
                // 创建并异步记录审计日志
                AuditLog log = AuditLogUtil.createAuditLog("user", Long.valueOf(id.toString()),
                        AuditLogUtil.OPERATION_TYPE_DELETE, beforeEntity, null);
                asyncAuditLogService.recordAuditLogAsync(log);
            } catch (Exception e) {
                // 记录异常但不影响主业务流程
                e.printStackTrace();
            }
        }
        
        return result;
    }
}